import ij.process.ImageProcessor;

import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Random;

public class Block {
    LinkedList<CoocurenceMatrix> matrices;
    Rectangle imageArea;
    double criteriaValue;
    //ImageProcessor imageProcessor;

    public Block() {
        imageArea = new Rectangle();
        matrices = new LinkedList<CoocurenceMatrix>();
    }

    public Block(int x, int y, int width, int height) {
        imageArea = new Rectangle(x, y, width, height);
        matrices = new LinkedList<CoocurenceMatrix>();
    }

    public Block setImageProcessor(ImageProcessor ip){
        //imageProcessor = ip;
        return this;
    }

    public int getPixelCount() {
        return imageArea.width * imageArea.height;
    }

    public void colorEdges(ImageProcessor imageProcessor, int id, int color){
        if(id >= 0){
            imageProcessor.setColor(color);
            for(int i = 0; i < 3; ++i){
                imageProcessor.drawRect(imageArea.x + i,imageArea.y + i,imageArea.width - 2*i,imageArea.height - 2*i);
            }

                imageProcessor.drawString(""+id,imageArea.x + 5,imageArea.y + 15);
        }
    }

//    public void color(int color){
//        int pixelColor;
//        for(int i = 0; i < getPixelCount(); ++i){
//            pixelColor = getPixel(i);
//            setPixel(i,combineColors(pixelColor,color));
//        }
//    }

//    public void setPixel(int i, int color){
//        if (i > getPixelCount())
//            return ;
//        int x = i % imageArea.width;
//        int y = i / imageArea.height;
//        x += imageArea.x;
//        y += imageArea.y;
//        imageProcessor.set(x, y, color);
//    }

    public int getPixel(ImageProcessor imageProcessor, int index) {
        if (index > getPixelCount())
            return 0;
        int x = index % imageArea.width;
        int y = index / imageArea.height;
        x += imageArea.x;
        y += imageArea.y;
        return imageProcessor.getPixel(x, y);
    }

    public int getPixelX(int index)
    {
        return (index % imageArea.width)+imageArea.x;
    }

    public int getPixelY(int index)
    {
        return (index % imageArea.height)+imageArea.y;
    }

    public CoocurenceMatrix calculateCoocurenceMatrix(ImageProcessor imageProcessor, int levels, CoocurenceMatrix.Direction direction, int distance)
    {
		CoocurenceMatrix matrix = new CoocurenceMatrix(levels);

		int x, y;
		for (int i = 0; i < getPixelCount(); ++i) {
			// TODO: czy jako sasiedzi liczone sa tez piksele nie nalezace do
			// bloku?
			x = getPixelX(i);
			y = getPixelY(i);
			// TODO: inne kierunki, na razie jest tylko poziomy

			switch (direction) {
			case HORIZONTAL: {
				matrix.inc(
						levelPixelByBrightness(
								getPixelBrightness(getPixel(imageProcessor, i)),
								levels),
						levelPixelByBrightness(
								getPixelBrightness(imageProcessor.getPixel(x
										+ distance, y)), levels));
				matrix.inc(
						levelPixelByBrightness(
								getPixelBrightness(getPixel(imageProcessor, i)),
								levels),
						levelPixelByBrightness(
								getPixelBrightness(imageProcessor.getPixel(x
										- distance, y)), levels));
				break;
			}
			case VERTICAL: {
				matrix.inc(
						levelPixelByBrightness(
								getPixelBrightness(getPixel(imageProcessor, i)),
								levels),
						levelPixelByBrightness(
								getPixelBrightness(imageProcessor.getPixel(x, y
										+ distance)), levels));
				matrix.inc(
						levelPixelByBrightness(
								getPixelBrightness(getPixel(imageProcessor, i)),
								levels),
						levelPixelByBrightness(
								getPixelBrightness(imageProcessor.getPixel(x, y
										- distance)), levels));
			}
			case LR_SLANTED: {
				matrix.inc(
						levelPixelByBrightness(
								getPixelBrightness(getPixel(imageProcessor, i)),
								levels),
						levelPixelByBrightness(
								getPixelBrightness(imageProcessor.getPixel(x
										- distance, y - distance)), levels));
				matrix.inc(
						levelPixelByBrightness(
								getPixelBrightness(getPixel(imageProcessor, i)),
								levels),
						levelPixelByBrightness(
								getPixelBrightness(imageProcessor.getPixel(x
										+ distance, y + distance)), levels));
			}
			case RL_SLANTED: {
				matrix.inc(
						levelPixelByBrightness(
								getPixelBrightness(getPixel(imageProcessor, i)),
								levels),
						levelPixelByBrightness(
								getPixelBrightness(imageProcessor.getPixel(x
										+ distance, y - distance)), levels));
				matrix.inc(
						levelPixelByBrightness(
								getPixelBrightness(getPixel(imageProcessor, i)),
								levels),
						levelPixelByBrightness(
								getPixelBrightness(imageProcessor.getPixel(x
										- distance, y + distance)), levels));
			}
			default: {
			}
				;
			}
		}
		return matrix;
    }

    public void calculateCriteria(ImageProcessor imageProcessor){
        double sum = 0;
        int blockPixelCount = getPixelCount();
        for (int i = 0; i < blockPixelCount; ++i) {
            /*color = new Color(block.getPixel(i));
                   sum += Color.RGBtoHSB(color.getRed(), color.getGreen(),
                           color.getBlue(), null)[2];*/
            sum += getPixelBrightness(getPixel(imageProcessor, i));
        }
        criteriaValue = sum / blockPixelCount;

    }

    private float getPixelBrightness(int pixelValue)
    {
        Color color = new Color(pixelValue);
        return Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null)[2];
    }

    private int levelPixelByBrightness(float brightness, int levels)
    {

        double v = 1.0f / (levels-1);
        return (int) (brightness / v);
    }

    public int levelPixelByBrightness(int levels)
    {
        return levelPixelByBrightness((float)criteriaValue, levels);
    }

//    private int combineColors(int x, int y){
//        int r,g,b;
//
//        r = ((x&0xff0000)>>16)+((y&0xff0000)>>16);
//        g = ((x&0x00ff00)>>8)+((y&0xff0000)>>16);
//        b = (x&0x0000ff)+(y&0x0000ff);
//        return (r<<16)|(g<<8)|b;
//
//    }

}